From One Report, Many

Using Parameterized Reporting to Generate
Dozens, Hundreds, or Thousands of Reports
at the Same Time

David Keyes // R for the Rest of Us

About Me

Why Parameterized Reporting?

Making multiple reports is tedious

Making multiple reports is error-prone

Making multiple reports is often not feasible

Parameterized Reporting Changes Everything

Or Imagine Having to Make One Report for Each NHS Trust in England

  [1] "RF4"    "R1H"    "AD913"  "RYX"    "RQM"    "RJ6"    "Y02696" "NX122" 
  [9] "RVR"    "RJ1"    "Y03082" "RQX"    "RY9"    "RYJ"    "RJZ"    "RAX"   
 [17] "RJ2"    "R1K"    "RP6"    "RAT"    "RAP"    "Y02973" "AF003"  "AF002" 
 [25] "RAL"    "Y03047" "RJ7"    "F84747" "RAS"    "Y03094" "E84068" "RKE"   
 [33] "RRV"    "Y02147" "Y03201" "NL7"    "8J094"  "RDD"    "RC1"    "M85813"
 [41] "RQ3"    "RJF"    "RGT"    "RFS"    "NQ108"  "RDE"    "Y03571" "RTG"   
 [49] "RY8"    "NNJ"    "RWH"    "NQ106"  "RLT"    "NTPAL"  "NEH06"  "RR1"   
 [57] "RY4"    "RQQ"    "RGQ"    "RGP"    "RNQ"    "C82038" "RY5"    "NJS05" 
 [65] "RC9"    "C82009" "NLO11"  "NLO09"  "RQ8"    "RD8"    "Y02652" "RM1"   
 [73] "RGN"    "RNS"    "NMH01"  "NR3"    "RX1"    "NLO10"  "C82010" "NLO12" 
 [81] "Y02428" "RXK"    "RK5"    "RXW"    "R1D"    "Y02615" "RJC"    "RAJ"   
 [89] "Y02470" "Y02961" "RNA"    "RQW"    "RCX"    "RL4"    "RWD"    "RRK"   
 [97] "RKB"    "RWE"    "RJE"    "RBK"    "ATQ02"  "RWG"    "RGR"    "RWP"   
[105] "RLQ"    "REM"    "RCF"    "RBS"    "RFF"    "RXL"    "RMC"    "RAE"   
[113] "NNF09"  "RY2"    "RWY"    "RW3"    "RLN"    "RJR"    "RXP"    "RNN"   
[121] "RP5"    "RJN"    "RXR"    "NNF28"  "RR7"    "RCD"    "RWA"    "RV9"   
[129] "RXN"    "Y01231" "RR8"    "Y02875" "RY1"    "REP"    "Y01069" "RBT"   
[137] "RXF"    "RNL"    "RVW"    "RTV"    "NLO01"  "RJL"    "RTF"    "RW6"   
[145] "RT2"    "AC008"  "RQ6"    "RM3"    "AXT02"  "RCU"    "RHQ"    "RTR"   
[153] "RE9"    "RVY"    "RBN"    "RWJ"    "RMP"    "RTD"    "RFR"    "RM2"   
[161] "RTX"    "RWW"    "RY7"    "RBL"    "AJN"    "RRF"    "RCB"    "RTK"   
[169] "Y02688" "NQT10"  "RWX"    "Y04538" "RXH"    "NLW"    "RXQ"    "Y00058"
[177] "NLT02"  "RJ8"    "RN7"    "RBD"    "RVV"    "RXC"    "DD401"  "RDU"   
[185] "R1J"    "RTE"    "RN3"    "RN5"    "NDA57"  "R1F"    "RYY"    "NR5"   
[193] "RWF"    "RPA"    "RVJ"    "RBZ"    "L83087" "RNU"    "RTH"    "NLX02" 
[201] "RK9"    "RD3"    "RHU"    "RPC"    "RHW"    "REF"    "RH8"    "RA2"   
[209] "RD1"    "RNZ"    "Y02666" "RH5"    "RYF"    "NTP11"  "RW1"    "NTPAD" 
[217] "RTP"    "RDR"    "RBA"    "AAH"    "RDZ"    "RA9"    "RHM"    "RA7"   
[225] "RYR"    "RA3"    "NDA56"  "G82071" "NDA55"  "NLX24"  "RA4"    "NAX"   
[233] "R1A"    "Y02646" "NTP08"  "Y02613" "RDY"    "Y02662" "Y02568" "Y02585"
[241] "RYW"    "NLO20"  "Y02987" "Y02596" "NLO02"  "Y02565" "E84069" "Y02692"
[249] "Y03218" "Y03007" "C83023" "NNF70"  "NNF94"  "NNF99"  "R0A"    "Y02532"
[257] "Y03645" "Y02572" "Y02533" "NQT5F"  "NNF76"  "NNF18"  "NTV0B"  "Y02676"
[265] "Y00751" "Y02816" "NDJ"    "Y03051" "NQT5H"  "Y02584" "NTV0W"  "NNFA7" 
[273] "RW4"    "AXG"   

Parameterized Reporting is the Solution

How Parameterized Reporting Works

Make a Report

---
title: "Total Admissions Over Time"
format: 
  html:
    embed-resources: true
    css: styles.css
execute: 
  echo: false
  warning: false
  message: false
editor_options: 
  chunk_output_type: console
---

```{r}
library(tidyverse)
library(NHSRdatasets)
library(scales)
```


This chart shows total admissions over time in all NHS trusts.

```{r}
ae_attendances %>% 
  summarize(total_admissions = sum(admissions),
            .by = period) %>% 
  ggplot(aes(x = period,
             y = total_admissions)) +
  geom_line(alpha = 0.9,
            color = "#005EB8") +
  geom_area(alpha = 0.5,
            fill = "#005EB8") +
  scale_y_continuous(labels = comma_format()) +
  theme_minimal(base_family = "Frutiger") +
  theme(plot.title = element_text(face = "bold"),
        plot.title.position = "plot",
        panel.grid.minor = element_blank(),
        panel.grid.major.x = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank())
```

Manually Render One Report

Make a Report for One Location

---
title: "Total Admissions Over Time"
format: 
  html:
    embed-resources: true
    css: styles.css
execute: 
  echo: false
  warning: false
  message: false
editor_options: 
  chunk_output_type: console
---

```{r}
library(tidyverse)
library(NHSRdatasets)
library(scales)
```

This chart shows total admissions over time at RF4.

```{r}
ae_attendances %>% 
  filter(org_code == "RF4") %>% 
  summarize(total_admissions = sum(admissions),
            .by = period) %>% 
  ggplot(aes(x = period,
             y = total_admissions)) +
  geom_line(alpha = 0.9,
            color = "#005EB8") +
  geom_area(alpha = 0.5,
            fill = "#005EB8") +
  scale_y_continuous(labels = comma_format()) +
  theme_minimal(base_family = "Frutiger") +
  theme(plot.title = element_text(face = "bold"),
        plot.title.position = "plot",
        panel.grid.minor = element_blank(),
        panel.grid.major.x = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank())
```

Add a Parameter to Our Report

---
title: "Total Admissions Over Time"
format: 
  html:
    embed-resources: true
    css: styles.css
execute: 
  echo: false
  warning: false
  message: false
editor_options: 
  chunk_output_type: console
params:
  location: "RF4"
---

```{r}
library(tidyverse)
library(NHSRdatasets)
library(scales)
```


This chart shows total admissions over time at `r params$location`.

```{r}
ae_attendances %>% 
  filter(org_code == params$location) %>% 
  summarize(total_admissions = sum(admissions),
            .by = period) %>% 
  ggplot(aes(x = period,
             y = total_admissions)) +
  geom_line(alpha = 0.9,
            color = "#005EB8") +
  geom_area(alpha = 0.5,
            fill = "#005EB8") +
  scale_y_continuous(labels = comma_format()) +
  theme_minimal(base_family = "Frutiger") +
  theme(plot.title = element_text(face = "bold"),
        plot.title.position = "plot",
        panel.grid.minor = element_blank(),
        panel.grid.major.x = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank())
```

Manually Render the Report (Again)

Manually Render Multiple Reports

Semi-Manually Render Report with R Script File

library(quarto)

quarto_render(
  input = "report.qmd",
  output_file = "RF4.html",
  execute_params = list(location = "RF4")
)

Automatically Render Multiple Reports with R Script File

# Load packages
library(tidyverse)
library(NHSRdatasets)
library(quarto)

# Create a vector of all locations
locations <- ae_attendances %>%
  distinct(org_code) %>% 
  mutate(org_code = as.character(org_code)) %>% 
  pull(org_code) 

# Create a tibble with information on the:
# input R Markdown document
# output HTML file
# parameters needed to knit the document
reports <- tibble(
  input = "report.qmd",
  output_file = str_glue("{locations}.html"),
  execute_params = map(locations, ~list(location = .))
)

# Use the tibble to generate all of our reports
pwalk(reports, quarto_render)

Summary

  1. Create report
  2. Add parameter to report
  3. Create render.R script file
  4. Create vector of all locations
  5. Create tibble with information about all reports
  6. Use reports tibble to render all reports

Learn More

Chapter from R Without Statistics ➜

GitHub Repository ➜

Don’t Do It By Hand, Use Parameterized Reporting

  • Less tedious

  • Less error-prone

  • Makes it possible to generate reports that would not otherwise be feasible

Questions?

Ask in the chat or by email: david@rfortherestofus.com